﻿namespace Bzstd.Utility.Assertion;

/// <summary>
/// 通用断言类
/// </summary>
public static partial class Assert
{
	/// <summary>
	/// 真值断言
	/// </summary>
	/// <param name="expression"></param>
	/// <param name="message"></param>
	/// <returns></returns>
	public static bool IsTrue(bool expression, string message)
	{
		return expression || Fail<bool>(message);
	}

	/// <summary>
	/// 假值断言
	/// </summary>
	/// <param name="expression"></param>
	/// <param name="message"></param>
	/// <returns></returns>
	public static bool IsFalse(bool expression, string message)
	{
		return !IsTrue(!expression, message);
	}

	/// <summary>
	/// 不为空断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T NotNull<T>(T obj, string message)
	{
		IsTrue(null != obj, message);
		return obj;
	}

	/// <summary>
	/// 为空断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T IsNull<T>(T obj, string message)
	{
		IsTrue(null == obj, message);
		return obj;
	}

	/// <summary>
	/// 相等断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="obj1"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T AreEqual<T>(T obj, object obj1, string message)
	{
		IsTrue(Equals(obj, obj1), message);
		return obj;
	}

	/// <summary>
	/// 不等断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="obj1"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T AreNotEqual<T>(T obj, object obj1, string message)
	{
		IsFalse(Equals(obj, obj1), message);
		return obj;
	}

	/// <summary>
	/// 引用相等断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="obj1"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T AreReferenceEqual<T>(T obj, object obj1, string message)
	{
		IsTrue(ReferenceEquals(obj, obj1), message);
		return obj;
	}

	/// <summary>
	/// 引用不等断言
	/// </summary>
	/// <param name="obj"></param>
	/// <param name="obj1"></param>
	/// <param name="message"></param>
	/// <typeparam name="T"></typeparam>
	/// <returns></returns>
	public static T AreNotReferenceEqual<T>(T obj, object obj1, string message)
	{
		IsFalse(ReferenceEquals(obj, obj1), message);
		return obj;
	}

	/// <summary>
	/// 遇到异常
	/// </summary>
	/// <returns></returns>
	public static T Catch<T>(Action action, string message) where T : Exception
	{
		try
		{
			action?.Invoke();
			return Fail<T>(message);
		}
		catch (T e)
		{
			return e;
		}
	}

	/// <summary>
	/// 遇到异常
	/// </summary>
	/// <returns></returns>
	public static Exception Catch(Action action, string message)
	{
		return Catch<Exception>(action, message);
	}

	/// <summary>
	/// 遇到异常
	/// </summary>
	/// <returns></returns>
	public static T Catch<T, R>(Func<R> func, string message) where T : Exception
	{
		return Catch<T>(() => func?.Invoke(), message);
	}

	/// <summary>
	/// 遇到异常
	/// </summary>
	/// <returns></returns>
	public static Exception Catch<R>(Func<R> func, string message)
	{
		return Catch<Exception, R>(func, message);
	}

	/// <summary>
	/// 未遇异常
	/// </summary>
	/// <returns></returns>
	public static void NotCatch<T>(Action action, string message) where T : Exception
	{
		try
		{
			action?.Invoke();
		}
		catch (T e)
		{
			Fail<T>(e, message);
		}
	}

	/// <summary>
	/// 未遇异常
	/// </summary>
	/// <returns></returns>
	public static void NotCatch(Action action, string message)
	{
		NotCatch<Exception>(action, message);
	}

	/// <summary>
	/// 未遇异常
	/// </summary>
	/// <returns></returns>
	public static R NotCatch<T, R>(Func<R> func, string message) where T : Exception
	{
		try
		{
			return func == null ? default : func.Invoke();
		}
		catch (T e)
		{
			return Fail<R>(e, message);
		}
	}

	/// <summary>
	/// 未遇异常
	/// </summary>
	/// <returns></returns>
	public static void NotCatch<R>(Func<R> func, string message)
	{
		NotCatch<Exception, R>(func, message);
	}

	/// <summary>
	/// 断言失败
	/// </summary>
	/// <returns></returns>
	public static T Fail<T>(Exception exception, string message)
	{
		throw new AssertionException(message + exception?.Message, exception);
	}

	/// <summary>
	/// 断言失败
	/// </summary>
	/// <returns></returns>
	public static T Fail<T>(string message)
	{
		return Fail<T>(null, message);
	}

	/// <summary>
	/// 断言失败
	/// </summary>
	/// <returns></returns>
	public static object Fail(string message)
	{
		return Fail<AssertionException>(message);
	}
}
